package com.teach.flavour.service.impl;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import com.teach.flavour.model.entity.AssociatorFlavourVector;
import com.teach.flavour.model.entity.FoodFlavourVector;
import com.teach.flavour.model.po.AssociatorFlavour;
import com.teach.flavour.dao.AssociatorFlavourDao;
import com.teach.flavour.model.dto.AssociatorFlavourDTO;
import com.teach.flavour.model.vo.LikeVO;
import com.teach.flavour.service.MPAssociatorFlavourService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.teach.flavour.dao.FlavourTagDao;
import com.teach.service.OrdersService;
import com.teach.util.cache.RedisCache;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * <p>
 *  会员口味表 服务实现类
 * </p>
 * @version 1.0
 * @author hzz
 * @since 2020-03-11
 */
@Service
public class AssociatorFlavourServiceImpl extends ServiceImpl<AssociatorFlavourDao, AssociatorFlavour> implements MPAssociatorFlavourService {
    @Autowired
    private AssociatorFlavourDao associatorFlavourDao;
    @Autowired
    private FlavourTagDao flavourTagDao;
    @Autowired
    private RedisCache redisCache;
    @Value("${redis.state}")
    private String redisState;
    private String redisRec="rec:as:";
    private String redisFlavour="fl:";

    public boolean saveValue(AssociatorFlavour entity){
        clac();
        return this.saveOrUpdate(entity);
    }
    public List<LikeVO> getLike(String associatorId){
        AssociatorFlavour associatorFlavour= associatorFlavourDao.get(associatorId);
        if(associatorFlavour!=null){
            //如果redis已经启用
            if("1".equals(redisState)){
                //获取推荐表达式（向量） 如：｛3，1，2｝
                return redisRecommend(associatorId);
            }
            return dbRecommend(associatorId);
        }else{
            return RandomRecommend();
        }
    }
    public List<LikeVO> redisRecommend(String id){
        List<LikeVO> likes=new ArrayList<>();
        Set<String> range = redisCache.range(redisRec + id, 0, -1);
        Iterator<String> iterator = range.iterator();
        while (iterator.hasNext()){
            String next = iterator.next();
            LikeVO o = (LikeVO)redisCache.get(redisFlavour+id+":" + next);
            likes.add(o);
        }
        return likes;
    }
    public List<LikeVO> dbRecommend(String associatorId){
        List<LikeVO> likes=baseMapper.getLike(associatorId);
        return likes;
    }
    public List<LikeVO> RandomRecommend(){
        List<LikeVO> likes=baseMapper.getLike("associator_0");
        return likes;
    }
    @Async
    public void clac(){
        List<FoodFlavourVector> allFoodVector = associatorFlavourDao.getAllFoodVector();
        List<AssociatorFlavourVector> allVector = associatorFlavourDao.getAllVector();
        if (allVector.isEmpty()){
            return;
        }else {
            allVector.forEach(as->{
                allFoodVector.forEach(f->{
                    double cos = cosineSimilarity(as.getVector(),f.getVector());
                    if (!(cos>1)){
                        LikeVO like=null;
                        System.out.println(String.format("%s(%s)的与%s(%s)的余弦相似度为：%1.4f",as.getAssociatorId(),as,f.getFoodsId(),f,cos));
                        if (redisCache.exists(redisFlavour+as.getAssociatorId()+":"+f.getFoodsId())){
                            like=(LikeVO)redisCache.get(redisFlavour+as.getAssociatorId()+":"+f.getFoodsId());
                        }else {
                            like=new LikeVO();
                        }
                        like.setFoodsId(f.getFoodsId());
                        like.setUrl(f.getUrl());
                        like.setTitle(f.getFoodsName());
                        like.setRecEL(""+as+f);
                        redisCache.add(redisRec+as.getAssociatorId(),f.getFoodsId(),cos);
                        redisCache.set(redisFlavour+as.getAssociatorId()+":"+f.getFoodsId(),like);
                    }
                });
            });
        }
    }
    public double cosineSimilarity(int[] as, int[] f){
        int []d=new int[as.length];
        long distance=0;
        for (int i=0;i<as.length;i++) {
            if (as[i]==0){
                d[i]=0;
            }else if (as[i]==f[i]){
                distance=0;
                break;
            }else{
                d[i]=as[i]-f[i];
            }
            distance+=d[i];
        }
        if(as==null||f==null||as.length!=f.length){
            return 2.0000;
        }
        long fenzi=0,left=0,right=0;
        for(int i=0;i<as.length;i++){
            if (as[i]!=0){
                fenzi+=as[i]*f[i];
            }
        }
        for(int i=0;i<as.length;i++){
            if (as[i]!=0){
                left+=as[i]*as[i];
                right+=f[i]*f[i];
            }
        }
        if(left*right==0){
            return 2.0000;
        }
        double result=fenzi/Math.sqrt(left*right);
        if (distance<=1&&distance>0){
            result=result/1.2;
        }else if(distance<=1){
            result=result/1.5;
        }else if (distance>1){
            result=-1.00001;
        }
        DecimalFormat df=new DecimalFormat("#.####");
        return Double.parseDouble(df.format(result));
    }
}
